package com.ssm.log;

import com.google.gson.Gson;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Component;

@Aspect
@Component
@Slf4j
@ConditionalOnProperty(name = {"log.aspect.enable"}, havingValue = "true", matchIfMissing = true)
public class LogAspect {

    //统一日志管理 在Controller service 和 微服务rpc调用的链路过程中打印参数等信息

    /*
    1/所有返回类型 public private等
    2.包名 com.ssm.*.controller
    3.类名 *Controller
    4.方法名(不限参数)  *(..)
    * */
    @Pointcut("execution(* com.ssm.*.controller.*Controller.*(..)) || execution(* com.ssm.*.service.*Service.*(..))")
    private void pointCut(){} //切点

    //使用环绕通知方式（before在方法前执行 after在方法后执行，around可自定义方法执行前后的操作，通过proceed执行切面方法）

    @Around("pointCut()")
    public Object around(ProceedingJoinPoint point) throws Throwable {
        Object[] reqArgs = point.getArgs(); //获取参数列表
        String req = new Gson().toJson(reqArgs); //Gson.toJson把java对象转化为json字符串

        //获取类名 + 方法名(强转为MethodSignature)
        MethodSignature signature = (MethodSignature) point.getSignature();
        String methodNames = signature.getDeclaringType().getName() + "." + signature.getName();

        //打印入参的  类名.方法名 和 参数req
        log.info("{},req:{}", methodNames, req);

        long start = System.currentTimeMillis(); //获取方法执行前时间

        Object responseObj = point.proceed(); //执行切面类方法
        String resp= new Gson().toJson(responseObj); //获取响应的json结果

        long end = System.currentTimeMillis(); //获取方法执行后时间

        //打印响应结果 和 执行时间
        log.info("{},response:{},costTime:{}", methodNames, req, end - start);

        //环绕通知  需要返回目标方法执行后的结果即point.proceed()的返回值，否则会出现空指针(获取完数据被日志切面截胡)
        return responseObj;
    }

}
